home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
tcsel003.zip
/
SEARCH.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-10-16
|
13KB
|
293 lines
program search;
{$A+,B-,D-,E+,F-,I+,L-,N-,O-,R-,S-,V-}
{$M 16384,0,655360}
{ Copyright 1990 Trevor J Carlsen Version 1.05 24-07-90 }
{ This program may be used and distributed as if it was in the Public Domain}
{ with the following exceptions: }
{ 1. If you alter it in any way, the copyright notice must not be }
{ changed. }
{ 2. If you use code excerpts in your own programs, due credit must be }
{ given, along with a copyright notice - }
{ "Parts Copyright 1990 Trevor J Carlsen" }
{ 3. No charge may be made for any program using code from this program.}
{ SEARCH will scan a file or group of files and report on all occurrences }
{ of a particular string or group of characters. If found the search string }
{ will be displayed along with the 79 characters preceding it and the 79 }
{ characters following the line it is in. Wild cards may be used in the }
{ filenames to be searched. }
{ If you find this program useful here is the author's contact address - }
{ Trevor J Carlsen }
{ PO Box 568 }
{ Port Hedland Western Australia 6721 }
{ Voice 61 [0]91 72 2026 }
{ Data 61 [0]91 72 2569 }
uses
dos,
tpstring, { Turbo Power's string handling library. Procedures and }
{ functions used from this unit are - }
{ BMSearch }
{ BMSearchUC }
{ BMMakeTable }
{ StUpcase }
tctimer; { A little timing routine - not needed if lines (**) removed. }
const
bufflen = 65000; { Do not increase this buffer size . Ok to decrease. }
searchlen = bufflen;
copyright1 = 'SEARCH - version 1.05 Copyright 1990 Trevor Carlsen';
copyright2 = 'All rights reserved.';
type
str79 = string[79];
buffertype = array[0..bufflen] of byte;
buffptr = ^buffertype;
const
space = #32;
quote = #34;
comma = #44;
CaseSensitive : boolean = true; { default is a case sensitive search }
var
table : BTable; { Boyer-Moore search table }
buffer : buffptr; { pointer to new buffer }
f : file;
DisplayStr : array[0..3] of str79;
filename,
SrchStr : string;
Slen : byte absolute SrchStr;
procedure Asc2Str(var s, ns; max: byte);
{ Converts an array of asciiz characters to a turbo string }
{ for speed the variable st is effectively global and it is therefore }
{ vitally important that max is no larger than the ns untyped parameter }
{ Failure to ensure this can result in unpredictable program behaviour }
var starray : array[0..255] of byte absolute s;
st : string absolute ns;
len : byte absolute st;
begin
move(starray[0],st[1],max);
len := max;
end; { Asc2Str }
procedure ReportError(e : byte);
{ Displays a simple instruction screen in the event of insufficient }
{ parameters or certain other errors }
begin
writeln('SYNTAX:');
writeln('SEARCH [-c] [path]filename searchstr');
writeln(' eg: SEARCH c:\comm\telix\salt.doc "color"');
writeln(' or');
writeln(' SEARCH c:\comm\telix\salt.doc 13,10,13,10,13,10,13,10');
writeln(' or');
writeln(' SEARCH -c c:\*.* "MicroSoft"');
writeln;
writeln('If the -c option is used then a case insensitive search is used.');
writeln('When used the -c option must be the first parameter.');
halt(e);
end; { ReportError }
procedure ParseCommandLine;
{ This procedure is really the key to everything as it parses the command }
{ line to determine what the string being searched for is. Because the }
{ wanted string can be entered in literal form or in ascii codes this will }
{ disect and determine the method used. }
var
parstr : string; { contains the command line }
len : byte absolute parstr;{ will contain the length of cmd line }
cpos, qpos,
spos, chval : byte;
error : integer;
begin { ParseCommandLine}
parstr := string(ptr(PrefixSeg,$80)^); { Get the command line }
if parstr[1] = space then
delete(parstr,1,1); { if the first character is a space get rid of it }
spos := pos(space,parstr); { find the first space }
if spos = 0 then { No spaces which must be an error }
ReportError(1);
filename := StUpCase(copy(parstr,1,spos-1)); { filename used as a temp }
if pos('-C',filename) = 1 then begin { Case insensitive search required }
CaseSensitive := false;
delete(parstr,1,spos); { Get rid of the used portion }
end; { if pos('-C' }
spos := pos(space,parstr); { find next space }
if spos = 0 then { No spaces which must be an error }
ReportError(1);
filename := StUpCase(copy(parstr,1,spos-1)); { Get the file mask }
delete(parstr,1,spos); { Get rid of the used portion }
qpos := pos(quote,parstr); { look for the first quote char }
if qpos <> 0 then begin { quote char found - so must be quoted text }
if parstr[1] <> quote then ReportError(2); { first char must be quote }
delete(parstr,1,1); { get rid of the first quote }
qpos := pos(quote,parstr); { and find the next quote }
if qpos = 0 then ReportError(3); { no more quotes - so it is an error }
SrchStr := copy(parstr,1,qpos-1); { search string now defined }
end { if qpos <> 0 }
else begin { must be using ascii codes }
Slen := 0;
cpos := pos(comma,parstr); { find first comma }
if cpos = 0 then cpos := succ(len);{ No comma - so only one ascii code }
repeat { create the search string }
val(copy(parstr,1,pred(cpos)),chval,error);
if error <> 0 then ReportError(7); { there is an error so bomb out }
inc(Slen);
SrchStr[Slen] := char(chval); { add char to the search string }
delete(parstr,1,cpos); { get rid of used portion of parstr }
cpos := pos(comma,parstr); { find the next comma }
if cpos = 0 then cpos := succ(len); { no more commas so last char }
until len = 0; { until whole of command line is processed }
end; { else}
if not CaseSensitive then { change the Search string to upper case }
SrchStr := StUpCase(SrchStr);
end; { ParseCommandLine }
function OpenFile(ofn : string): boolean; { open a file for BlockRead/Write }
var
error : word;
begin { OpenFile}
assign(f,ofn);
{$I-} reset(f,1); {$I+}
error := IOResult;
if error <> 0 then
writeln('Cannot open ',ofn);
OpenFile := error = 0;
end; { OpenFile }
procedure CloseFile;
begin
{$I-}
Close(f);
if IOResult <> 0 then; { don't worry too much if an error occurs here }
{$I+}
end; { CloseFile }
procedure SearchFile(var filename: string);
{ Reads a file into the buffer and then searches that buffer for the wanted}
{ string or characters. }
var
x,y,
count,
result,
bufferpos : word;
abspos : longint;
finished : boolean;
begin { SearchFile}
BMMakeTable(SrchStr,table); { Create a Boyer-Moore search table }
new(buffer); { make room on the heap for the buffers }
{$I-} BlockRead(f,buffer^,searchlen,result); {$I+} { Fill buffer buffer }
if IOResult <> 0 then begin { error occurred while reading the file }
CloseFile;
ReportError(11);
end; { if IOResult }
abspos := 0; { Initialise the absolute file position marker }
repeat
bufferpos := 0; { position marker in current buffer }
count := 0; { offset from search starting point }
finished := (result < searchlen); { if buffer <> full no more reads }
repeat { Do a BM search for search string }
if CaseSensitive then { do a case sensitive search }
count:=BMSearch(buffer^[bufferpos],result-bufferpos,table,SrchStr)
else { do a case insensitive search }
count:=BMSearchUC(buffer^[bufferpos],result-bufferpos,table,SrchStr);
if count <> $FFFF then begin { search string found }
inc(bufferpos,count); { starting point of SrchStr in buffer }
DisplayStr[0] := HexL(abspos+bufferpos) + { hex and decimal pos }
form(' @######',(abspos+bufferpos) * 1.0);
if bufferpos > 79 then { there is a line available before }
Asc2Str(buffer^[bufferpos - 79],DisplayStr[1],79)
else { no line available before the found }
DisplayStr[1] := ''; { position so null the string }
if (bufferpos + 79) < result then { at least 79 chars can be }
Asc2Str(buffer^[bufferpos],DisplayStr[2],79) { displayed }
else { only display what is left in buffer }
Asc2Str(buffer^[bufferpos],DisplayStr[2],result - bufferpos);
if (bufferpos + 158) < result then { display the line following }
Asc2Str(buffer^[bufferpos + 79],DisplayStr[3],79)
else { no line following the found string }
DisplayStr[3] := ''; { so null the display string }
writeln;
writeln(DisplayStr[0],' ',filename);{ display the file locations }
for x := 1 to 3 do begin
for y := 1 to length(DisplayStr[x]) do{ filter out non-printables}
if ord(DisplayStr[x][y]) < 32 then DisplayStr[x][y] := '.';
if length(DisplayStr[x]) <> 0 then { only display strings with }
writeln(DisplayStr[x]); { valid content }
end; { for x }
inc(bufferpos,Slen); { no need to check buffer in found st }
end; { if count <> $ffff }
until (bufferpos >= (result-length(SrchStr))) or (count = $ffff);
if not finished then begin { Fill 'er up again for another round }
inc(abspos,result - Slen); { create overlap so no string missed }
{$I-} seek(f,abspos);
BlockRead(f,buffer^,searchlen,result); {$I+}
if IOResult <> 0 then begin
CloseFile;
ReportError(13);
end;
end; { if not finished}
until finished;
dispose(buffer);
end; { SearchFile }
procedure SearchForFiles;
var
dirinfo : SearchRec;
FullName: PathStr;
DirName : DirStr;
FName : NameStr;
ExtName : ExtStr;
found : boolean;
begin
FindFirst(filename,AnyFile,dirinfo);
found := DosError = 0;
if not found then begin
writeln('Cannot find ',filename);
ReportError(255);
end;
FSplit(filename,DirName,FName,ExtName);
while found do begin
if (dirinfo.Attr and 24) = 0 then begin
FullName := DirName + dirinfo.name;
if OpenFile(FullName) then begin
SearchFile(FullName);
CloseFile;
end;
end;
FindNext(dirinfo);
found := DosError = 0;
end;
end; { SearchForFiles }
begin { main}
(**) StartTimer;
writeln(copyright1);
writeln(copyright2);
ParseCommandLine;
SearchForFiles;
(**) WriteElapsedTime;
end.